home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 5 / Apprentice-Release5.iso / Source Code / C / Applications / Python 1.3.3 / Python 133 68K / Mac / scripts / MkDistr.py < prev    next >
Text File  |  1996-05-20  |  6KB  |  281 lines

  1. #
  2. # Interactively decide what to distribute
  3. #
  4. # The distribution type is signalled by a letter. The currently
  5. # defined letters are:
  6. # p        PPC normal distribution
  7. # P        PPC development distribution
  8. # m        68K normal distribution
  9. # M        68K development distribution
  10. #
  11. # The exclude file signals files to always exclude,
  12. # The pattern file records are of the form
  13. # ('pm', '*.c')
  14. # This excludes all files ending in .c for normal distributions.
  15. #
  16. # The include file signals files and directories to include.
  17. # Records are of the form
  18. # ('pPmM', 'Lib')
  19. # This includes the Lib dir in all distributions
  20. # ('pPmM', 'Tools:bgen:AE:AppleEvents.py', 'Lib:MacToolbox:AppleEvents.py')
  21. # This includes the specified file, putting it in the given place.
  22. #
  23. from MkDistr_ui import *
  24. import fnmatch
  25. import regex
  26. import os
  27. import sys
  28. import macfs
  29. import macostools
  30.  
  31. SyntaxError='Include/exclude file syntax error'
  32.  
  33. class Matcher:
  34.     """Include/exclude database, common code"""
  35.     
  36.     def __init__(self, type, filename):
  37.         self.type = type
  38.         self.filename = filename
  39.         self.rawdata = []
  40.         self.parse(filename)
  41.         self.rawdata.sort()
  42.         self.rebuild()
  43.         self.modified = 0
  44.  
  45.     def parse(self, dbfile):
  46.         try:
  47.             fp = open(dbfile)
  48.         except IOError:
  49.             return
  50.         data = fp.readlines()
  51.         fp.close()
  52.         for d in data:
  53.             d = d[:-1]
  54.             if not d or d[0] == '#': continue
  55.             pat = self.parseline(d)
  56.             self.rawdata.append(pat)
  57.                 
  58.     def parseline(self, line):
  59.         try:
  60.             data = eval(line)
  61.         except:
  62.             raise SyntaxError, line
  63.         if type(data) <> type(()) or len(data) not in (2,3):
  64.             raise SyntaxError, line
  65.         if len(data) == 2:
  66.             data = data + ('',)
  67.         return data
  68.         
  69.     def save(self):
  70.         fp = open(self.filename, 'w')
  71.         for d in self.rawdata:
  72.             fp.write(`d`+'\n')
  73.         self.modified = 0
  74.             
  75.     def add(self, value):
  76.         if len(value) == 2:
  77.             value = value + ('',)
  78.         self.rawdata.append(value)
  79.         self.rebuild1(value)
  80.         self.modified = 1
  81.         
  82.     def delete(self, value):
  83.         key = value
  84.         for i in range(len(self.rawdata)):
  85.             if self.rawdata[i][1] == key:
  86.                 del self.rawdata[i]
  87.                 self.unrebuild1(i, key)
  88.                 self.modified = 1
  89.                 return
  90.         print 'Not found!', key
  91.                 
  92.     def getall(self):
  93.         return map(lambda x: x[1], self.rawdata)
  94.     
  95.     def get(self, value):
  96.         for t, src, dst in self.rawdata:
  97.             if src == value:
  98.                 return t, src, dst
  99.         print 'Not found!', value
  100.                 
  101.     def is_modified(self):
  102.         return self.modified
  103.                             
  104. class IncMatcher(Matcher):
  105.     """Include filename database and matching engine"""
  106.  
  107.     def rebuild(self):
  108.         self.idict = {}
  109.         self.edict = {}
  110.         for v in self.rawdata:
  111.             self.rebuild1(v)
  112.             
  113.     def rebuild1(self, (tp, src, dst)):
  114.         if self.type in tp:
  115.             if dst == '':
  116.                 dst = src
  117.             self.idict[src] = dst
  118.         else:
  119.             self.edict[src] = ''
  120.             
  121.     def unrebuild1(self, num, src):
  122.         if self.idict.has_key(src):
  123.             del self.idict[src]
  124.         else:
  125.             del self.edict[src]
  126.     
  127.     def match(self, patharg):
  128.         removed = []
  129.         # First check the include directory
  130.         path = patharg
  131.         while 1:
  132.             if self.idict.has_key(path):
  133.                 # We know of this path (or initial piece of path)
  134.                 dstpath = self.idict[path]
  135.                 # We do want it distributed. Tack on the tail.
  136.                 while removed:
  137.                     dstpath = os.path.join(dstpath, removed[0])
  138.                     removed = removed[1:]
  139.                 # Finally, if the resultant string ends in a separator
  140.                 # tack on our input filename
  141.                 if dstpath[-1] == os.sep:
  142.                     dir, file = os.path.split(path)
  143.                     dstpath = os.path.join(dstpath, path)
  144.                 return dstpath
  145.             path, lastcomp = os.path.split(path)
  146.             if not path:
  147.                 break
  148.             removed[0:0] = [lastcomp]
  149.         # Next check the exclude directory
  150.         path = patharg
  151.         while 1:
  152.             if self.edict.has_key(path):
  153.                 return ''
  154.             path, lastcomp = os.path.split(path)
  155.             if not path:
  156.                 break
  157.             removed[0:0] = [lastcomp]
  158.         return None
  159.             
  160.     def checksourcetree(self):
  161.         rv = []
  162.         for name in self.idict.keys():
  163.             if not os.path.exists(name):
  164.                 rv.append(name)
  165.         return rv
  166.                 
  167. class ExcMatcher(Matcher):
  168.     """Exclude pattern database and matching engine"""
  169.  
  170.     def rebuild(self):
  171.         self.relist = []
  172.         for v in self.rawdata:
  173.             self.rebuild1(v)
  174.         
  175.     def rebuild1(self, (tp, src, dst)):
  176.         if self.type in tp:
  177.             pat = fnmatch.translate(src)
  178.             self.relist.append(regex.compile(pat))
  179.         else:
  180.             self.relist.append(None)
  181.             
  182.     def unrebuild1(self, num, src):
  183.         del self.relist[num]
  184.     
  185.     def match(self, path):
  186.         comps = os.path.split(path)
  187.         file = comps[-1]
  188.         for pat in self.relist:
  189.             if pat and pat.match(file) == len(file):
  190.                 return 1
  191.         return 0        
  192.          
  193.         
  194. class Main:
  195.     """The main program glueing it all together"""
  196.     
  197.     def __init__(self):
  198.         InitUI()
  199.         fss, ok = macfs.GetDirectory('Source directory:')
  200.         if not ok:
  201.             sys.exit(0)
  202.         os.chdir(fss.as_pathname())
  203.         self.typedist = GetType()
  204.         print 'TYPE', self.typedist
  205.         self.inc = IncMatcher(self.typedist, '(MkDistr.include)')
  206.         self.exc = ExcMatcher(self.typedist, '(MkDistr.exclude)')
  207.         self.ui = MkDistrUI(self)
  208.         self.ui.mainloop()
  209.         
  210.     def check(self):
  211.         return self.checkdir(':', 1)
  212.         
  213.     def checkdir(self, path, istop):
  214.         files = os.listdir(path)
  215.         rv = []
  216.         todo = []
  217.         for f in files:
  218.             if self.exc.match(f):
  219.                 continue
  220.             fullname = os.path.join(path, f)
  221.             if self.inc.match(fullname) == None:
  222.                 if os.path.isdir(fullname):
  223.                     todo.append(fullname)
  224.                 else:
  225.                     rv.append(fullname)
  226.         for d in todo:
  227.             if len(rv) > 100:
  228.                 if istop:
  229.                     rv.append('... and more ...')
  230.                 return rv
  231.             rv = rv + self.checkdir(d, 0)
  232.         return rv
  233.         
  234.     def run(self, destprefix):
  235.         missing = self.inc.checksourcetree()
  236.         if missing:
  237.             print '==== Missing source files ===='
  238.             for i in missing:
  239.                 print i
  240.             print '==== Fix and retry ===='
  241.             return
  242.         if not self.rundir(':', destprefix, 0):
  243.             return
  244.         self.rundir(':', destprefix, 1)
  245.  
  246.     def rundir(self, path, destprefix, doit):
  247.         files = os.listdir(path)
  248.         todo = []
  249.         rv = 1
  250.         for f in files:
  251.             if self.exc.match(f):
  252.                 continue
  253.             fullname = os.path.join(path, f)
  254.             if os.path.isdir(fullname):
  255.                 todo.append(fullname)
  256.             else:
  257.                 dest = self.inc.match(fullname)
  258.                 if dest == None:
  259.                     print 'Not yet resolved:', fullname
  260.                     rv = 0
  261.                 if dest:
  262.                     if doit:
  263.                         print 'COPY ', fullname
  264.                         print '  -> ', os.path.join(destprefix, dest)
  265.                         macostools.copy(fullname, os.path.join(destprefix, dest), 1)
  266.         for d in todo:
  267.             if not self.rundir(d, destprefix, doit):
  268.                 rv = 0
  269.         return rv
  270.         
  271.     def save(self):
  272.         self.inc.save()
  273.         self.exc.save()
  274.         
  275.     def is_modified(self):
  276.         return self.inc.is_modified() or self.exc.is_modified()
  277.  
  278. if __name__ == '__main__':
  279.     Main()
  280.     
  281.